package blue.squares;

import android.view.View;
import android.graphics.*;
import android.graphics.drawable.Drawable;
import android.content.Context;
import android.content.res.Resources;

/**
 *
 * @author Luisa Lu
 */
class ScreenView extends View {
    // ------------------------------------------------------------------------
    // Constants.
    // ------------------------------------------------------------------------

    static final float BORDER_PERCENT = 0.02f;
    static final boolean ALWAYS_DISPLAY_AS_LIST = true;
    static final int VERSUS_SCORE_FONT_SIZE = 48;
    static final int LIST_SCORE_FONT_SIZE  = 24;

    // ------------------------------------------------------------------------
    // Fields.
    // ------------------------------------------------------------------------

    final Paint _brush;
    private Drawable _pieceImages[];

    int _screenW;
    int _screenH;
    int _canvasW;
    int _canvasH;
    int _topHeight;

    float _cell;
    float _corner;
    float _len;
    float _border;

    Game _game;
    int _boardSize;

    // ------------------------------------------------------------------------
    // Implementation.
    // ------------------------------------------------------------------------

    public ScreenView(Context context) {
        super(context);
        _brush = new Paint();
        _brush.setAntiAlias(true);

        Resources res = context.getResources();
        _pieceImages = new Drawable[]{
            res.getDrawable(R.drawable.p0),
            res.getDrawable(R.drawable.p1)
        };
    }
    
    public void setGame(Game game){
        _game = game;
        _boardSize = _game.getBoardSize();
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        _screenW = w;
        _screenH = h;
        _topHeight = Math.abs(_screenH - _canvasH);
        Util.logDebug(this, "onSizeChanged: screen = "+_screenW+"x"+_screenH+" "+oldw+"x"+oldh+" top = "+_topHeight);
    }

    @Override
    protected void onDraw(Canvas canvas){
        _canvasW = canvas.getWidth();
        _canvasH = canvas.getHeight();
        _topHeight = Math.abs(_screenH - _canvasH);
        Util.logVerbose(this, "onDraw: canvas = "+_canvasW+"x"+_canvasH+" top = "+_topHeight);

        _len = Math.min(_canvasW, _canvasH-_topHeight);
        _border = _len * BORDER_PERCENT;
        _cell = (_len - 2* _border) / _boardSize;
        _corner = _border + _cell/2;

        int save = canvas.save();
        drawBoard(canvas);

        canvas.restoreToCount(save);
        //noinspection PointlessBooleanExpression
        if(ALWAYS_DISPLAY_AS_LIST || _game.getPlayerCount()>2)
             drawScoreAsList(canvas);
        else drawScoreAsVersus(canvas);
    }

    private void drawBoard(Canvas canvas){
        // Draw background.
        canvas.drawColor(Color.BLACK);

        // Change to grid coordinates.
        canvas.translate(_corner, _corner);
        canvas.scale(_cell, _cell);

        // Draw grid lines.
        _brush.setColor(Color.argb(128,255,255,255));
        _brush.setStyle(Paint.Style.STROKE);
        _brush.setStrokeWidth(0); // single pixel
        for(int i = 0; i < _boardSize; i++){
            canvas.drawLine(0, i, _boardSize-1, i, _brush);
            canvas.drawLine(i, 0, i, _boardSize-1, _brush);
        }

        // Highlight selected squares.
        {
            Player p = _game.getPlayerAtLoc(_game.getSelected());
            Game.Square[] squares = _game.getSelectedSquares();
            if(p != null && squares != null) {
                int c = p.getColor();
                _brush.setColor(Color.argb(128, Color.red(c), Color.green(c), Color.blue(c)));
                _brush.setStyle(Paint.Style.STROKE);
                _brush.setStrokeWidth(0.2f); // 20% of cell (1 unit)
                canvas.drawPath(convertToPath(squares), _brush);
            }
        }

        // Show currently selected location.
        {
            Player p = _game.getCurrentPlayer();
            int c = (p != null)? p.getColor() : Color.rgb(128,128,128);
            _brush.setColor(Color.argb(128, Color.red(c), Color.green(c), Color.blue(c)));
            _brush.setStyle(Paint.Style.STROKE);
            _brush.setStrokeWidth(0.1f);
            Point cen = _game.getSelected();
            canvas.drawCircle((float)cen.x, (float)cen.y, 0.45f, _brush);
        }

        // Draw pieces.  We scale the grid here because we can only
        // blit at integer coordinates.
        canvas.scale(0.01f, 0.01f);
        for(int x = 0; x < _boardSize; x++){
            for(int y = 0; y < _boardSize; y++){
                Player p = _game.getPlayerAtLoc(new Point(x, y));
                if(p != null) {
                    Drawable d = _pieceImages[p.getId()];
                    int l = 35;
                    d.setBounds(100*x-l, 100*y-l, 100*x+l, 100*y+l);
                    d.draw(canvas);
                }
            }
        }
    }

    private void drawScoreAsVersus(Canvas canvas){
        // setup font for score
        _brush.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
        _brush.setTextSize(VERSUS_SCORE_FONT_SIZE);
        _brush.setStyle(Paint.Style.FILL);

        // get strings
        Player currentPlayer = _game.getCurrentPlayer();
        Player p1 = _game.getPlayer(0);
        Player p2 = _game.getPlayer(1);
        String seg1 = ""+p1.getScore();
        String seg2 = " : ";
        String seg3 = ""+p2.getScore();
        float totalWidth = getStringWidth(seg1+seg2+seg3, _brush);

        // move to text area and set alignment
        if(_canvasH > _canvasW){
            canvas.translate((_len-totalWidth)/2,
                             _len+_border+VERSUS_SCORE_FONT_SIZE);
        }else{
            canvas.translate(_len+_border*2, 
                            (_canvasH-VERSUS_SCORE_FONT_SIZE)/2);
        }

        // draw strings
        _brush.setUnderlineText(p1.equals(currentPlayer));
        float loc = drawText(0, p1.getColor(), seg1, canvas);
        _brush.setUnderlineText(false);
        loc = drawText(loc, Color.WHITE, seg2, canvas);
        _brush.setUnderlineText(p2.equals(currentPlayer));
        drawText(loc, p2.getColor(), seg3, canvas);
    }

    private void drawScoreAsList(Canvas canvas){
        // setup font for score
        _brush.setTypeface(Typeface.create(Typeface.SANS_SERIF, Typeface.BOLD));
        _brush.setTextSize(LIST_SCORE_FONT_SIZE);
        _brush.setStyle(Paint.Style.FILL);
        Paint.FontMetrics fm = _brush.getFontMetrics();
        float lineHeight = _brush.getFontMetrics(fm);

        // move to text area and set alignment
        if(_canvasH > _canvasW){
            canvas.translate(_border+_cell/2,
                             _len+_border+LIST_SCORE_FONT_SIZE);
        }else{
            canvas.translate(_len+_border,
                            (_canvasH-LIST_SCORE_FONT_SIZE)/2);
        }

        // print player and highlight current
        Player currentPlayer = _game.getCurrentPlayer();
        for(int i = 0; i < _game.getPlayerCount(); i++){
            Player p = _game.getPlayer(i);
            String star = (p.equals(currentPlayer)) ? ">" : "  ";
            String text = star+"Player "+(i+1)+" : "+p.getScore();
            drawText(0, p.getColor(), text, canvas);
            canvas.translate(0, lineHeight);
        }
    }

    private float drawText(float loc, int color, String text, Canvas canvas){
        _brush.setColor(color);
        canvas.drawText(text, 0, text.length(), loc, 0, _brush);
        return loc+getStringWidth(text, _brush);
    }

    public float[] screenToGrid(float x, float y){
        y -= _topHeight;
        return new float[]{(x-_corner)/_cell, (y-_corner)/_cell};
    }
    
    // ------------------------------------------------------------------------
    // Static implementation.
    // ------------------------------------------------------------------------

    private static float getStringWidth(String text, Paint paint){
        int l = text.length();
        float[] w = new float[l];
        paint.getTextWidths(text, 0, l, w);
        float total = 0;
        for (float aW : w) {
            total += aW;
        }
        return total;
    }

    private static Path convertToPath(Game.Square[] squares){
        Path path = new Path();
        path.setFillType(Path.FillType.WINDING);
        for (Game.Square square : squares) {
            path.moveTo(square.a.x, square.a.y);
            path.lineTo(square.b.x, square.b.y);
            path.lineTo(square.c.x, square.c.y);
            path.lineTo(square.d.x, square.d.y);
            path.lineTo(square.a.x, square.a.y);
        }
        path.close();
        return path;
    }

}
